package com.tabnet.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.joda.time.DateTime;

import com.tabnet.beans.personnes.Adresse;
import com.tabnet.beans.personnes.Client;
import com.tabnet.dao.DAOAdresse;
import com.tabnet.dao.DAOClient;
import com.tabnet.dao.DAOException;
import com.tabnet.dao.DAOFactory;
import com.tabnet.dao.DAOUtilitaire;

public class ClientDAOImpl implements DAOClient {
	private static final String SQL_SELECT        		= "SELECT IDClient, AdresseID, NomC, PrenomC, TelephoneC, NaissanceC, MailC, MDP FROM Client ORDER BY IDClient";
	private static final String SQL_INSERT_CLIENT	 	= "INSERT INTO Client (IDClient, AdresseID, NomC, PrenomC, TelephoneC, NaissanceC, MailC, MDP) VALUES (?, ?, ?, ?, ?, ?, ?, MD5(?));";
	private static final String SQL_MAIL 				= "SELECT IDClient FROM Client WHERE MailC = ?";
	private static final String SQL_ID 					= "SELECT IDClient FROM Client WHERE IDClient = ?";
	private static final String SQL_CLIENT				= "SELECT IDClient, AdresseID, NomC, PrenomC, TelephoneC, NaissanceC, MailC, MDP FROM Client WHERE IDClient = ?";
	private static final String SQL_MDP					= "SELECT IDClient FROM Client WHERE MailC = ? AND MDP = MD5(?)";
	private static final String SQL_VERIF_MDP			= "SELECT MDP FROM Client WHERE IDClient = ? AND MDP = MD5(?)";
	private static final String SQL_MODIF_CLIENT		= "UPDATE Client SET NomC = ?, PrenomC = ?, TelephoneC = ?, NaissanceC = ?, MailC = ?, MDP = MD5(?) WHERE IDClient = ?";
    private static final String FORMAT_DATE_BDD         = "yyyy-MM-dd";
    
    private DAOFactory daoFactory;
    private static DAOAdresse daoAdresseClient;

    public ClientDAOImpl( DAOFactory daoFactory ) {
        this.daoFactory = daoFactory;
        ClientDAOImpl.daoAdresseClient = daoFactory.getAdresseDAO();
    }

    /**
     * <p>Fonction static map<br />
     * Simple méthode utilitaire permettant de faire la correspondance (le
     * mapping) entre une ligne issue de la table des client (un ResultSet) et
     * un bean Client.</p>
     * @param resultSet : objet ResultSet
	 * @return objet client
	 * @throws SQLException
     */
    private static Client map( ResultSet resultSet ) throws SQLException {
    	Client oClient = new Client();

    	oClient.setId(resultSet.getInt("IDClient"));
    	oClient.setNom(resultSet.getString("NomC"));
    	oClient.setPrenom(resultSet.getString("PrenomC"));
    	oClient.setTelephone(resultSet.getString("TelephoneC"));
    	oClient.setNaissance(new DateTime(resultSet.getDate("NaissanceC")));
    	
		try {
			oClient.setAdresse(ClientDAOImpl.daoAdresseClient.trouverAdr(resultSet.getInt( "AdresseID" )));
		} catch (DAOException e) {
			e.printStackTrace();
		}
    	
		oClient.setMail( resultSet.getString( "MailC" ) );
		oClient.setMDP( resultSet.getString( "MDP" ) );
		
        return oClient;
    }

    @Override
	public void addClient(Client pClient) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet valeursAutoGenerees = null;
        
        try {
        	oConnexion = this.daoFactory.getConnection();
            Adresse oAdresse = pClient.getAdresse();
            
            //insertion adresse client
            ClientDAOImpl.daoAdresseClient.addAdresse(oAdresse);
            
            //insertion client
            oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_INSERT_CLIENT, true,
            		pClient.getId(),  oAdresse.getId(), pClient.getNom(), pClient.getPrenom(), pClient.getTelephone(), 
            		pClient.getNaissance().toString(FORMAT_DATE_BDD), pClient.getMail(), pClient.getMDP());
            
            if ( oPreparedStatement.executeUpdate() == 0 )
                throw new DAOException( "Échec de la création du client, aucune ligne ajoutée dans la table." );
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses( valeursAutoGenerees, oPreparedStatement, oConnexion );
        }
	}

	@Override
	public void updClient(Client pClient, String pMDP, boolean pModifmdp) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultMDP = null;
        ResultSet valeursAutoGenerees = null;

        try {
        	oConnexion = this.daoFactory.getConnection();
            Adresse adr = pClient.getAdresse();
            
            //Modification de l'adresse
            ClientDAOImpl.daoAdresseClient.updAdresse(adr);
            
            // modification client
            if(pMDP != null){
            	
            	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_VERIF_MDP, false, pClient.getId(), pMDP);
            	oResultMDP = oPreparedStatement.executeQuery();

            	//Si le mot de passe renseigné est correct
                if ( oResultMDP.next() ){
                		
	            	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_MODIF_CLIENT, true,
		            		pClient.getNom(), pClient.getPrenom(), pClient.getTelephone(), pClient.getNaissance().toString(FORMAT_DATE_BDD),
		            		pClient.getMail(), (pMDP == pClient.getMDP() || pModifmdp) ? pClient.getMDP() : pMDP, pClient.getId());
	            	
		            if ( oPreparedStatement.executeUpdate() == 0 )
		                throw new DAOException( "Échec de la modification du client, aucune ligne modifiée dans la table." );
                }
                else
	                throw new DAOException( "Le mot de passe renseigné est incorrect." );
            }
            else
                throw new DAOException( "Renseigné le mot de passe à la fin du formulaire pour valider." );
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses( valeursAutoGenerees, oPreparedStatement, oConnexion );
        }
	}

    @Override
    public Map<Integer, Client> getClients() throws DAOException {
    	Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;
        Map<Integer, Client> mapClients = new HashMap<Integer, Client>();
        Client oClient = null;

        try {
        	oConnexion = this.daoFactory.getConnection();
            // récupération des clients

        	oPreparedStatement =  DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_SELECT, false );
        	//oPreparedStatement = oConnection.prepareStatement( SQL_SELECT );
        	oResultSet = oPreparedStatement.executeQuery();
        	
            while ( oResultSet.next() ) {
            	oClient = map( oResultSet );
            	mapClients.put(oClient.getId(), oClient);
            }
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses( oResultSet, oPreparedStatement, oConnexion );
        }

        return mapClients;
    }

	@Override
	public boolean checkId(int pId) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;

        try {
        	oConnexion = daoFactory.getConnection();
        	
        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_ID, true, pId);
        	oResultSet = oPreparedStatement.executeQuery();
        	
            /* Parcours de la ligne de données retournée dans le ResultSet */
            if ( oResultSet.next() )
            	return false;
            else
            	return true;
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses( oResultSet, oPreparedStatement, oConnexion );
        }
	}

	@Override
	public boolean checkMail(String pMail, int pId) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;

        try {
        	oConnexion = this.daoFactory.getConnection();

        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_MAIL, true, pMail);
        	oResultSet = oPreparedStatement.executeQuery();
        	
            /* Parcours de la ligne de données retournée dans le ResultSet */
        	oResultSet.getRow();
            if ( oResultSet.next() ) {
            	// si l'adresse mail correspond à ce client c'est ok
            	if(oResultSet.getString("IDClient").equals(pId))
            		return true;
            	else
            		return false;
            }
            return true;
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses( oResultSet, oPreparedStatement, oConnexion );
        }
	}

	@Override
	public int checkMdp(String pMail, String pMDP) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;
        int idClient = 0;

        try {
        	oConnexion = this.daoFactory.getConnection();

        	oPreparedStatement =  DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_MDP, false, pMail, pMDP );
        	        	
        	oResultSet = oPreparedStatement.executeQuery();

            /* Parcours de la ligne de données retournée dans le ResultSet */
            if ( oResultSet.next() )
            	idClient = oResultSet.getInt("IDClient");
            else
                throw new DAOException( "Client inexistant." );
            
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses( oResultSet, oPreparedStatement, oConnexion );
        }

        return idClient;
	}

	@Override
	public Client getClient(int pId) throws DAOException {
		if(pId == 0)
			return null;
		else {
			Connection oConnexion = null;
	        PreparedStatement oPreparedStatement = null;
	        ResultSet oResultSet = null;
	        Client oClient = new Client();

	        try {
	        	oConnexion = this.daoFactory.getConnection();

	        	oPreparedStatement =  DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_CLIENT, false, pId );
	        	oResultSet = oPreparedStatement.executeQuery();
	        	
	            /* Parcours de la ligne de données retournée dans le ResultSet */
	            if ( oResultSet.next() )
	            	oClient = ClientDAOImpl.map(oResultSet);
	            
	        }
	        catch ( SQLException e ) {
	            throw new DAOException( e );
	        }
	        finally {
	            DAOUtilitaire.fermeturesSilencieuses( oResultSet, oPreparedStatement, oConnexion );
	        }

	        return oClient;
		}
	}
}
